#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "Translation.h"
#include "BMCIStringSynth.h"
#include "JIT.h"
#include "../BMCIR.h"
#include "../../JRYNES.h"
#include "../../Statistics.h"

extern Statistics* ExecutionStatistics;
extern EmulationSettings Settings;

void TRL_Init(){
    JIT_Init();
}

//This function is responsible for optimizing BMC code by inserting contextual
//information. Only the context is passed since it contains a pointer to its BMC
void TRL_OptimizationRequest(ExeContext* Context){
    char* Code, *Filename;
    
    if(Context->SourceBMC){
        ExecutionStatistics->DBT_OptimizedContexts++;
        Code = BIS_Synthesize(Context->SourceBMC, BISSF_MACROS | BISSF_JUMPTABLE, Context);
        JIT_CompileBlockOPT(Code, Context->SourceBMC, JITCF_PIPE, Context);
        Filename = JIT_GetDynLibName(Context->SourceBMC, "./dynlib/" ,"ctx", Context->ECXContextHash);
        Context->Code = JIT_DynamicLink(Filename, Context->SourceBMC->IR->FunctionName);
    }
    else{
        fprintf(stderr, "Fatal ERROR: Optimization Requests are only possible for existing blocks of machine code.\n");
        exit(1);
    }
    
}

void TRL_TranslationRequest(BMCList *BlockList){
    uint32_t i, NB;
    
    NB = BMCLNumBlocks(BlockList);
    
    //Translate every block
    for(i = 0; i < NB; i++){
        BMCIR* IR;
        char* Filename;
        
        if(!(BlockList->Blocks[i]))
            continue;
        
        IR = BMCIRNew();
        BlockList->Blocks[i]->IR = IR;
        
        ExecutionStatistics->DBT_EffectiveBMCs++;
        
        if(BlockList->Blocks[i]->Length >= Settings.CompilationThreshold){
            
            ExecutionStatistics->DBT_CompiledBlocks++;
            ExecutionStatistics->DBT_CompiledBytes += BlockList->Blocks[i]->BlockSize;
            ExecutionStatistics->DBT_CompiledInstructions += BlockList->Blocks[i]->Length;
            
            //Generate an Instruction String for the Current BMC
            //IR->CompleteSource = BIS_Synthesize(BlockList->Blocks[i], BISSF_PRECOMPILED | BISSF_JUMPTABLE, NULL);
            IR->CompleteSource = BIS_Synthesize(BlockList->Blocks[i], BISSF_MACROS | BISSF_JUMPTABLE, NULL);

            //if(BlockList->Blocks[i]->Pure)
            //    IR->PartialSource  = BIS_Synthesize(BlockList->Blocks[i], BISSF_MACROS | BISSF_INCOMPLETE, NULL);

            //Compile the current BMC to host machine code
            //JIT_CompileBlockF(IR->CompleteSource, BlockList->Blocks[i], 0);
            JIT_CompileBlockF(IR->CompleteSource, BlockList->Blocks[i], JITCF_PIPE);

            //if(BlockList->Blocks[i]->Pure)
            //    JIT_CompileBlockM(IR->PartialSource, BlockList->Blocks[i], JITCF_PIPE);

            BMCIRSetFunctionName(IR, BlockList->Blocks[i]->StartAddr);

            //Link the current BMC to the emulator core.
            Filename = JIT_GetDynLibName(BlockList->Blocks[i], "./dynlib/" ,"pcc", 0);
            BlockList->Blocks[i]->CompleteECTXTUnoptimized = JIT_DynamicLink(Filename, IR->FunctionName);

            //if(BlockList->Blocks[i]->Pure){
            //    free(Filename);
            //    Filename = JIT_GetDynLibName(BlockList->Blocks[i], "./dynlib/", "m");
            //    BlockList->Blocks[i]->PartialECTXTUnoptimized =  JIT_DynamicLink(Filename, IR->FunctionName);
            //}

            free(Filename);
        }
        
    }
    
    BMCLDestroy(BlockList);
    
}